<?php
/**
 * Date: 2024.8
 * Author: kahn
 */
namespace service\vip\payment;

use config\Config;
use config\Payment;
use config\Order;
use WeChat\Exceptions\InvalidResponseException;
use WeChat\Exceptions\LocalCacheException;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Writer\PngWriter;

class WxpayService extends \Service{

    /**
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function payApp($price, $sn, $desc): array
    {
        $payment = \WePayV3\Order::instance(Payment::WXPAY_V3);

        $result = $payment->create('app', [
            'appid'        => Config::WX_PLATFORM[Config::WX_PLATFORM_ANDROID_APP]['appId'],
            'mchid'        => Payment::WXPAY_V3['mch_id'],
            'description'  => $desc,
            'out_trade_no' => $sn,
            'notify_url'   => \Yaf_Registry::get("config")->server->url . Payment::WXPAY_V3['notify_uri'],
            'amount'       => ['total' => $price, 'currency' => 'CNY'],
        ]);

        return $result;

    }

    /**
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function payH5($price, $sn, $desc): array
    {
        $payment = \WePayV3\Order::instance(Payment::WXPAY_V3);

        // 4. 组装支付参数
        $result = $payment->create('h5', [
            'appid'        => Config::WX_PLATFORM[Config::WX_PLATFORM_WAP]['appId'],
            'mchid'        => Payment::WXPAY_V3['mch_id'],
            'description'  => $desc,
            'out_trade_no' => $sn,
            'notify_url'   =>  \Yaf_Registry::get("config")->server->url . Payment::WXPAY_V3['notify_uri'],
            'amount'       => ['total' => $price, 'currency' => 'CNY'],
            'scene_info'   => [
                'h5_info'         => [
                    'type' => 'Wap',
                ],
                'payer_client_ip' => '14.23.150.211',
            ],
        ]);

        return $result;
    }

    /**
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function payNative($price, $sn, $desc): array
    {
        $payment = \WePayV3\Order::instance(Payment::WXPAY_V3);

        // 4. 组装支付参数
        $result = $payment->create('native', [
            'appid'        => Config::WX_PLATFORM[Config::WX_PLATFORM_WEB]['appId'],
            'mchid'        => Payment::WXPAY_V3['mch_id'],
            'description'  => $desc,
            'out_trade_no' => $sn,
            'notify_url'   => \Yaf_Registry::get("config")->server->url . Payment::WXPAY_V3['notify_uri'],
            'amount'       => ['total' =>$price, 'currency' => 'CNY'],
        ]);
        if($result && isset($result['code_url'])){
            $qrcode = Builder::create()->data($result['code_url'])->writer(new PngWriter())->build()->getDataUri();
            $result['qrcode'] = $qrcode;
        }
        return $result;
    }

    /**
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function payJsapi($price, $sn, $desc, $openid, $payWay): array
    {

        $appId = $payWay == Order::PAY_WAY_MICRO ?
            Config::WX_PLATFORM[Config::WX_PLATFORM_MICRO]['appId'] :
                Config::WX_PLATFORM[Config::WX_PLATFORM_PUBLIC]['appId'];
        $config = Payment::WXPAY_V3;
        $config['appid'] = $appId;
        $payment = \WePayV3\Order::instance($config);
        // 4. 组装支付参数
        //$order = (string)time();
        $result = $payment->create('jsapi', [
            'appid'        => $appId,
            'mchid'        => Payment::WXPAY_V3['mch_id'],
            'description'  => $desc,
            'out_trade_no' => $sn,
            'notify_url'   => \Yaf_Registry::get("config")->server->url . Payment::WXPAY_V3['notify_uri'],
            'payer'        => ['openid' => $openid],
            'amount'       => ['total' => $price, 'currency' => 'CNY'],
        ]);

        return $result;

    }

    /**
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function pay($payWay, $price, $sn, $desc, $openId=''): ?array
    {
        $res = null;
        $price = $price * 100; //元转换成分
        switch ($payWay){
            case Order::PAY_WAY_APP:
                $res = $this->payApp($price, $sn, $desc);
                break;
            case Order::PAY_WAY_WEB:
                $res = $this->payNative($price, $sn, $desc);
                break;
            case Order::PAY_WAY_WAP:
                $res = $this->payH5($price, $sn, $desc);
                break;
            case Order::PAY_WAY_MICRO:
            case Order::PAY_WAY_PUBLIC:
                $res = $this->payJsapi($price, $sn, $desc, $openId, $payWay);
                break;
        }
        \Log::debug("pay weixin server return ", $res);
        return $res;
    }

    public function notify(): ?array
    {
        try {
            // 3. 创建接口实例
            $payment = \WePayV3\Order::instance(Payment::WXPAY_V3);
            $data = $payment->notify();
            \Log::info('wxpay notify ',$data);
            if(!$data || !$data['result']){
                return null;
            }

            if ($data['result']['trade_state'] == 'SUCCESS') {
                $sn = $data['result']['out_trade_no'];
                $price =$data['result']['amount']['total'] / 100; //分转换成元
                $tradeno = $data['result']['transaction_id'];
                $paidTime = strtotime($data['result']['success_time']);

                return [$sn, $price, $tradeno, $paidTime];
            }else{
                \Log::error("wxpay notify error, status error ", $data);
                return null;
            }
        } catch (\Exception $e) {
            \Log::error("wxpay notify error, verify error ", $e->getMessage());
            return null;

        }

    }

    public static function successResponse(): string
    {
        return json_encode(['code'=>'SUCCESS', 'message'=>'成功']);
    }

    public static function failedResponse(): string
    {
        return json_encode(['code'=>'FAIL', 'message'=>'失败']);
    }

    /**
     * @param $out_trade_no
     * @return array
     * @throws InvalidResponseException
     * @throws LocalCacheException
     */
    public function query($out_trade_no): ?array
    {
        $order = \WePayV3\Order::instance(Payment::WXPAY_V3);
        $data = $order->query($out_trade_no);
        if(!$data){
            return null;
        }
        if($data['trade_state'] == 'SUCCESS'){
            $sn = $data['out_trade_no'];
            $price = $data['amount']['total'] / 100; //分转换成元
            $tradeno = $data['transaction_id']; //订单号
            $paidTime = strtotime($data['success_time']);

            return [$sn, $price, $tradeno, $paidTime];
        }

        return null;
    }

    /**
     * 微信公众号授权获取openId
     * @return void
     */
    public static function publicAuthorize()
    {
        $appId = Config::WX_PLATFORM[Config::WX_PLATFORM_PUBLIC]['appId'];
        //$redirectUrl = \Yaf_Registry::get("config")->server->url . Config::WX_PLATFORM[Config::WX_PLATFORM_PUBLIC]['redirectUri'];
        $redirectUrl = "https://apiuc.zejicert.cn";
        $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appId&redirect_uri=$redirectUrl&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
        self::_curlGet($url);
    }


    /**
     * @param $code
     * @return mixed|null
     */
   public static function getPublicOpenId($code): ?string
   {
       $config = Config::WX_PLATFORM[Config::WX_PLATFORM_PUBLIC];
       $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$config['appId']}&secret={$config['secret']}&code={$code}&grant_type=authorization_code";

       $res = self::_curlGet($url);
       \Log::debug("getPublicOpenId $code", $res);
       if(!$res){
           \Log::error("get public openId error 1 ", $res);
           return null;
       }
       $auth = json_decode($res,true);
       if(!$auth || !isset($auth['openid'])){
           \Log::error("get public openId error 2 ", $res);
           return null;
       }

       return $auth['openid'];
   }

    /**
     * @param $code
     * @return mixed|null
     */
   public static function getMicroOpenId($code): ?string
   {
       $config = Config::WX_PLATFORM[Config::WX_PLATFORM_MICRO];

       $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$config['appId']}&secret={$config['secret']}&js_code=$code&grant_type=authorization_code";

       $res = self::_curlGet($url);
       \Log::debug("getMicroOpenId $code", $res);
       if(!$res){
           \Log::error("get Micro openId error 1 ", $res);
           return null;
       }
       $auth = json_decode($res,true);
       if(!$auth || (isset($auth['errcode']) and $auth['errcode'] != 0)){
           \Log::error("get Micro openId error 2 ", $res);
           return null;
       }

       return $auth['openid'];
   }

    /**
     * @param $url
     * @param $params
     * @return bool|string
     */
    private static function _curlGet($url, $params=null): bool|string
    {
        $curl = curl_init();

        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_USERAGENT, 'AuthClient');
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_HEADER, 0);

        if($params){
            $url = $url . '?' . http_build_query($params);
        }

        curl_setopt($curl, CURLOPT_URL, $url );

        $response = curl_exec($curl);

        curl_close($curl);

        return $response;
    }


}